# -*- coding: utf-8 -*-


# cmap2owl -- Helper application to convert from concept maps to OWL ontologies
# Copyright (c) 2008-2013  Rodrigo Rizzi Starr
#  
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#  
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#  
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.


'''
A class implementing a question

@author: Rodrigo Rizzi Starr
@copyright: Copyright © 2008-2013 Rodrigo Rizzi Starr
@license: MIT License
@contact: rodrigo.starr@gmail.com
'''


from __future__ import division
import time
import sys

# GTK+ imports
import pygtk
if not sys.platform == 'win32':
    pygtk.require('2.0')
try:
    import gtk
    import gtk.glade
    import gobject 
except:
    sys.exit(1)
    
# Project imports
from prologWrapper import Prolog
from log import log

log.debug("Loaded...")


def updateOnlyIfNecessary(func):
    """Updates the modification time in question class, only if there is 
        something newer"""
    def wrapper(*arg):
        "Renew the modification time"
        
        self = arg[0]
        if not Prolog.isUpToDate(self.lastUpdated):
            func(*arg)
            self.lastUpdated = time.time()
    
    return wrapper

class Question(gtk.Frame):
    """Implements a question answering structure which signalizes when an
        an answer was given.
        
        As a matter of fact, this class is both the view and the model of the
          question, so it is not a very good design. Maybe I refactor it latter
        """
    
    __gsignals__ = {"changed" : (gobject.SIGNAL_RUN_LAST,
                                 gobject.TYPE_NONE,
                                 (gobject.TYPE_BOOLEAN,)),
                                 }
    
    def __init__(self):
        gtk.Frame.__init__(self)
        self.app = None # The AppGui instance
        self.cmap = None # The CMapDraw instance
        self.label = None
        self.middle = None
        self.buttons = None
        self.menu = None # The context menu
        
        self.lastUpdated = 0.0 # The timestamp of the last update
            
    def build(self):
        "Creates the widgets"
        
        # Initialize the data
#        self.createData()
        
        # Builds the EventBox
        self.eBox = gtk.EventBox()
        self.eBox.set_visible_window(False)
#        self.eBox.set_above_child(True)
        self.eBox.connect("enter-notify-event", self.onEnter)
        self.eBox.connect("leave-notify-event", self.onLeave)
        self.eBox.connect("button-press-event", self.onButtonPress)
        self.add(self.eBox)
        
        # Builds the VBox
        self.vBox = gtk.VBox(spacing=2)
        self.vBox.set_property("width-request", 300)
        self.eBox.add(self.vBox)
        
        # Now adds each of the components. The label at the top, the middle and
        # the buttons at the bottom
        self.label = self.createLabel()
        if self.label != None:
            self.label.connect("enter-notify-event", self.onEnter)
            self.label.connect("leave-notify-event", self.onLeave)
            self.vBox.pack_start(self.label)

        self.middle = self.createMiddle()
        if self.middle != None:
            self.middle.connect("enter-notify-event", self.onEnter)
            self.middle.connect("leave-notify-event", self.onLeave)
            self.vBox.pack_start(self.middle)

        self.buttons = self.createButtons()
        if self.buttons != None and len(self.buttons) > 0:
            self.buttonBar = gtk.HBox()
            
            # Fetch the buttons and add them to the bar
            # The pack_end is used so we can add the undo button at the left
            for button in reversed(self.buttons):
                button.connect("enter-notify-event", self.onEnter)
                button.connect("leave-notify-event", self.onLeave)
                self.buttonBar.pack_end(button, expand=False)
                
            self.buttonBar.pack_end(gtk.HBox(), expand=True) # Space
            
            self.vBox.pack_start(self.buttonBar)
        
        # Finally creates the context menu
        self.menu = self.createMenu()
        
        # Guarantees that the info of the class is up-to-date
        self.update()
    
    @updateOnlyIfNecessary
    def createData(self):
        "Creates the data that will be used by the application"
        pass
    
    def createLabel(self):
        "Return the label that will be used (top part of the question)"
        return ""
    
    def createMiddle(self):
        "Creates the middle part of the dialog. It is usually null"
        return None
    
    def createButtons(self):
        "Returns a list with the buttons that will be used"
        return []
    
    def createMenu(self):
        "Returns a popup menu to be attached to the event box"
        return None
    
    def onEnter(self, widget = None, event = None):
        "Execute any necessary action when entering the widget"
        pass
    
    def onLeave(self, widget = None, event = None):
        "Execute any necessary action when leaving the widget"
        pass

    def onButtonPress(self, widget = None, event = None):
        "Shows the context menu"
        if event != None and \
           event.button == 3 and \
           isinstance(self.menu, gtk.Menu):
            self.menu.popup(None, None, None, event.button, event.time)
            return True
        return False
     
    # This is the part of a question lifecycle where it is updated
    def update(self):
        """Updates the question. It is called by the interface every time the
            data in the prolog database changes. """
        self.updateData()
        
        self.updateLabel()
        self.updateMiddle()
        self.updateButtons()
        self.updateMenu()
        
        self.updateSensitivity()
    
    @updateOnlyIfNecessary
    def updateData(self):
        "Updates the data used by this question"
        pass
        
    def updateLabel(self):
        "If necessary, changes the label of the question"
        pass
    
    def updateMiddle(self):
        "If necessary, changes the middle of the question"
        pass
    
    def updateButtons(self):
        "If necessary, changes the buttons of the question"
        pass

    def updateMenu(self):
        "If necessary, changes the context menu of the question"
        pass
    
    @updateOnlyIfNecessary
    def updateSensitivity(self):
        "Recalculates the status when the question was changed"
        pass
    
    def __eq__(self, element):
        if type(self) != type(element):
            return False
        else:
            return True
        
